FUNCTION save2nc, filename, mode, var1, var2, var3, var4, var5, _EXTRA=vars

; Save variables into a NetCDF file.
; variables (var1-5, vars) must be in numeric types.
; **** Sting and expression(for var1-5) are NOT supported ****
;
; Parameters
; ----------
; filename: STRING
; mode:     STRING ['a' | 'w']
;   file operation mode:
;   'a' for appending data to the file (create one if not exists),
;   'w' for writing data to a file (covered if exists).
; var1-5:   data, OPTIONAL, up limit 5 (defined by 'pos_vars_limit').
;   save data with its own name, i.e. var1 use 'var1' as its name in file.
;   so, var1-5 should not be an expression.
; _Extra = vars: keyword arguments, OPTIONAL
;   set (key, value) pairs to save `value with name `key
;
; EXAPMLES
; --------
; IDL> save2nc('file.nc', 'w', a, b=1+2, c=var1+var2)
;   ; create 'file.nc' with data: 'a': a, 'b': 3, 'c': var1+var2
;
; UPDATE:
;   - CREATED 2016/07/29    J.G. Chen, cjgls@pku.edu.cn
;       Any bugs report and suggestion are gladly welcome.

  pos_vars_limit = 5

  IF (N_PARAMS() LT 2) OR (N_PARAMS() GT pos_vars_limit +2) THEN BEGIN
    PRINT, FORMAT='("At least TWO but NOT more than" (I3) " are required!)', $
        pos_vars_limit + 2 ; total position args limit
    RETURN, 1
  ENDIF
  IF (N_PARAMS()) EQ 2 AND (N_ELEMENTS(vars) EQ 0) THEN BEGIN
    PRINT, "No data passed to the function!"
    RETURN, 1
  ENDIF

  ; filetypes = '(\.nc|\.cdl|\.cdf|\.ncdf|\.netcdf)$'

  IF NOT STREGEX(filename, '\.nc$', /BOOL) THEN BEGIN
    ; filename not with file type subfix
    filename = filename + '.nc'
  ENDIF

  up_mode = STRUPCASE(mode)
  IF (STRPOS(up_mode, 'A') GE 0) AND (FILE_TEST(filename)) THEN BEGIN
  ; 'append' mode and target file exists.
    fid = FILE_OPEN(filename, /write)
  ENDIF ELSE IF (STREGEX(up_mode, 'W') GE 0) THEN BEGIN
    fid = FILE_OPEN(filename, /write, /create)
  ENDIF ELSE BEGIN
    PRINT, "Not avaiable mode: ", mode
    RETURN, 1
  ENDELSE

  ; save var1-5 if exists.
  varname=''
  s = 0

  FOR i = 1, N_PARAMS() - 2 DO BEGIN
    istr = STRTRIM(STRING(i, FORMAT='(I)'), 2)
    command = "varname = SCOPE_VARNAME(var"+ istr + ", LEVEL=-1)"
    void = EXECUTE(command) ; get varname

    s = FILE_WRITE(fid, varname[0], SCOPE_VARFETCH('var'+istr) )

    IF s NE 0 THEN BEGIN
        PRINT, "ERROR: can not write '" + varname[0] + "' to file"
        file_close, fid
        RETURN, 1
    ENDIF
  ENDFOR

  ; save keyword defined vars
  ; `vars is a structure
  IF N_ELEMENTS(vars) THEN BEGIN
    tags = TAG_NAMES(vars)
    FOR i = 0, N_ELEMENTS(tags) - 1 DO BEGIN
        istr = STRTRIM(STRING(i, FORMAT='(I)'), 2)
        command = "s = FILE_WRITE(fid, tags[" + istr +"], vars." + tags[i] + ")"
        void = EXECUTE(command)

        IF s NE 0 THEN BEGIN
            PRINT, "ERROR: can not write '" + tags[i] + "' to file"
            file_close, fid
            RETURN, 1
        ENDIF
    ENDFOR
  ENDIF
  file_close, fid
  RETURN, 0

END
